{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 嵌套子图 (Nested Subplots) 教程\n",
        "\n",
        "本部分将详细讲解如何创建嵌套子图，即在子图中再创建子图。嵌套子图常用于放大显示局部区域或创建复杂的布局。\n",
        "\n",
        "## 学习内容\n",
        "1. **使用 fig.add_subplot() 创建嵌套子图**\n",
        "   - 在现有子图中添加新的子图\n",
        "   - 使用相对位置和大小\n",
        "\n",
        "2. **使用 axes.inset_axes() 创建嵌套子图**\n",
        "   - 在指定坐标轴内创建子图\n",
        "   - 更灵活的位置和大小控制\n",
        "\n",
        "3. **使用场景**\n",
        "   - 放大显示局部区域\n",
        "   - 创建复杂的图表布局\n",
        "   - 添加细节视图\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 导入必要的库\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "from matplotlib.patches import Rectangle\n",
        "\n",
        "# 设置中文字体（如果需要显示中文）\n",
        "plt.rcParams['font.sans-serif'] = ['PingFang SC', 'Arial Unicode MS']\n",
        "plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题\n",
        "\n",
        "# 在 Jupyter Notebook 中内联显示图形\n",
        "%matplotlib inline\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 第一部分：使用 fig.add_subplot() 创建嵌套子图\n",
        "\n",
        "`fig.add_subplot()` 可以在图形对象上直接添加子图，通过指定位置和大小来创建嵌套效果。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 1.1 fig.add_subplot() 基本语法\n",
        "\n",
        "`fig.add_subplot()` 可以在图形对象上添加子图，支持多种位置指定方式。\n",
        "\n",
        "**基本语法**：\n",
        "```python\n",
        "ax = fig.add_subplot(nrows, ncols, index)  # 标准方式\n",
        "ax = fig.add_subplot(position)  # 使用位置元组\n",
        "```\n",
        "\n",
        "**位置参数**：\n",
        "- `nrows, ncols, index`：标准子图网格方式\n",
        "- `position`：位置元组 `[left, bottom, width, height]`（相对于图形，0-1 之间）\n",
        "\n",
        "**使用场景**：\n",
        "- 创建不规则布局\n",
        "- 在现有子图基础上添加新的子图\n",
        "- 创建嵌套效果\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 1：使用 fig.add_subplot() 创建嵌套子图\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 创建主图形\n",
        "fig = plt.figure(figsize=(12, 8))\n",
        "\n",
        "# 创建主图（占据大部分空间）\n",
        "ax_main = fig.add_subplot(2, 2, (1, 3))  # 占据左侧两行\n",
        "ax_main.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "ax_main.set_title('主图：占据左侧两行', fontsize=14, fontweight='bold')\n",
        "ax_main.set_xlabel('x 轴', fontsize=12)\n",
        "ax_main.set_ylabel('y 轴', fontsize=12)\n",
        "ax_main.grid(True, alpha=0.3)\n",
        "\n",
        "# 在右上角创建嵌套子图\n",
        "ax_sub1 = fig.add_subplot(2, 2, 2)\n",
        "ax_sub1.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "ax_sub1.set_title('嵌套子图 1：右上角', fontsize=12)\n",
        "ax_sub1.grid(True, alpha=0.3)\n",
        "\n",
        "# 在右下角创建嵌套子图\n",
        "ax_sub2 = fig.add_subplot(2, 2, 4)\n",
        "ax_sub2.plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "ax_sub2.set_title('嵌套子图 2：右下角', fontsize=12)\n",
        "ax_sub2.set_ylim(-5, 5)\n",
        "ax_sub2.grid(True, alpha=0.3)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 1.2 使用位置元组创建嵌套子图\n",
        "\n",
        "使用位置元组 `[left, bottom, width, height]` 可以更精确地控制嵌套子图的位置和大小。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 2：使用位置元组创建嵌套子图\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 创建主图形\n",
        "fig = plt.figure(figsize=(12, 8))\n",
        "\n",
        "# 主图：占据整个图形的大部分\n",
        "ax_main = fig.add_axes([0.1, 0.1, 0.6, 0.8])  # [left, bottom, width, height]\n",
        "ax_main.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "ax_main.set_title('主图：使用位置元组 [0.1, 0.1, 0.6, 0.8]', fontsize=14, fontweight='bold')\n",
        "ax_main.set_xlabel('x 轴', fontsize=12)\n",
        "ax_main.set_ylabel('y 轴', fontsize=12)\n",
        "ax_main.grid(True, alpha=0.3)\n",
        "\n",
        "# 嵌套子图 1：右上角\n",
        "ax_sub1 = fig.add_axes([0.75, 0.6, 0.2, 0.3])  # [left, bottom, width, height]\n",
        "ax_sub1.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "ax_sub1.set_title('嵌套子图 1', fontsize=10)\n",
        "ax_sub1.grid(True, alpha=0.3)\n",
        "\n",
        "# 嵌套子图 2：右下角\n",
        "ax_sub2 = fig.add_axes([0.75, 0.1, 0.2, 0.3])  # [left, bottom, width, height]\n",
        "ax_sub2.plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "ax_sub2.set_title('嵌套子图 2', fontsize=10)\n",
        "ax_sub2.set_ylim(-5, 5)\n",
        "ax_sub2.grid(True, alpha=0.3)\n",
        "\n",
        "plt.suptitle('使用位置元组创建嵌套子图', fontsize=16, fontweight='bold', x=0.5, y=0.95)\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 第二部分：使用 axes.inset_axes() 创建嵌套子图\n",
        "\n",
        "`axes.inset_axes()` 是在现有坐标轴内创建嵌套子图的推荐方法，它提供了更灵活的控制。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 2.1 axes.inset_axes() 基本语法\n",
        "\n",
        "`axes.inset_axes()` 在指定的坐标轴内创建一个新的子图。\n",
        "\n",
        "**基本语法**：\n",
        "```python\n",
        "ax_inset = ax.inset_axes(bounds)\n",
        "ax_inset = ax.inset_axes([x0, y0, width, height])\n",
        "```\n",
        "\n",
        "**参数说明**：\n",
        "- `bounds`：位置和大小，格式为 `[x0, y0, width, height]`\n",
        "  - `x0, y0`：子图左下角的位置（相对于父坐标轴，0-1 之间）\n",
        "  - `width, height`：子图的宽度和高度（相对于父坐标轴，0-1 之间）\n",
        "\n",
        "**返回值**：\n",
        "- 返回新创建的坐标轴对象\n",
        "\n",
        "**优势**：\n",
        "- 位置和大小是相对于父坐标轴的，更容易控制\n",
        "- 适合在现有子图中添加细节视图\n",
        "- 代码更简洁\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 3：使用 axes.inset_axes() 创建嵌套子图\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 创建主图\n",
        "fig, ax = plt.subplots(figsize=(10, 6))\n",
        "ax.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "ax.set_title('主图：使用 inset_axes() 创建嵌套子图', fontsize=14, fontweight='bold')\n",
        "ax.set_xlabel('x 轴', fontsize=12)\n",
        "ax.set_ylabel('y 轴', fontsize=12)\n",
        "ax.grid(True, alpha=0.3)\n",
        "\n",
        "# 在右上角创建嵌套子图\n",
        "ax_inset = ax.inset_axes([0.6, 0.6, 0.35, 0.35])  # [x0, y0, width, height]\n",
        "ax_inset.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "ax_inset.set_title('嵌套子图', fontsize=10)\n",
        "ax_inset.grid(True, alpha=0.3)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 2.2 放大显示局部区域（最常用场景）\n",
        "\n",
        "嵌套子图最常见的用途是放大显示主图的局部区域，这在数据可视化中非常有用。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 4：放大显示局部区域\n",
        "x = np.linspace(0, 10, 1000)  # 增加点数以便放大时更平滑\n",
        "y = np.sin(x) + 0.1 * np.random.randn(len(x))  # 添加一些噪声\n",
        "\n",
        "# 创建主图\n",
        "fig, ax = plt.subplots(figsize=(12, 6))\n",
        "ax.plot(x, y, 'b-', linewidth=1.5, alpha=0.7, label='完整数据')\n",
        "ax.set_title('主图：完整数据视图', fontsize=14, fontweight='bold')\n",
        "ax.set_xlabel('x 轴', fontsize=12)\n",
        "ax.set_ylabel('y 轴', fontsize=12)\n",
        "ax.grid(True, alpha=0.3)\n",
        "ax.legend()\n",
        "\n",
        "# 标记要放大的区域\n",
        "x_zoom = [2, 4]\n",
        "y_zoom = [ax.get_ylim()[0], ax.get_ylim()[1]]\n",
        "rect = Rectangle((x_zoom[0], y_zoom[0]), x_zoom[1] - x_zoom[0], \n",
        "                 y_zoom[1] - y_zoom[0], linewidth=2, \n",
        "                 edgecolor='red', facecolor='none', linestyle='--')\n",
        "ax.add_patch(rect)\n",
        "ax.text(x_zoom[1], y_zoom[1], '放大区域', fontsize=10, \n",
        "        color='red', ha='left', va='bottom')\n",
        "\n",
        "# 创建嵌套子图，放大显示局部区域\n",
        "ax_inset = ax.inset_axes([0.55, 0.5, 0.4, 0.4])\n",
        "# 只绘制放大区域的数据\n",
        "mask = (x >= x_zoom[0]) & (x <= x_zoom[1])\n",
        "ax_inset.plot(x[mask], y[mask], 'r-', linewidth=2, label='放大视图')\n",
        "ax_inset.set_xlim(x_zoom[0], x_zoom[1])\n",
        "ax_inset.set_ylim(np.min(y[mask]) - 0.2, np.max(y[mask]) + 0.2)\n",
        "ax_inset.set_title('局部放大视图', fontsize=12, fontweight='bold')\n",
        "ax_inset.set_xlabel('x 轴', fontsize=10)\n",
        "ax_inset.set_ylabel('y 轴', fontsize=10)\n",
        "ax_inset.grid(True, alpha=0.3)\n",
        "ax_inset.legend(fontsize=9)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 2.3 多个嵌套子图\n",
        "\n",
        "可以在一个主图中创建多个嵌套子图，用于显示不同的细节或相关数据。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 5：多个嵌套子图\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 创建主图\n",
        "fig, ax = plt.subplots(figsize=(14, 8))\n",
        "ax.plot(x, np.sin(x), 'b-', linewidth=2, label='sin(x)')\n",
        "ax.plot(x, np.cos(x), 'r-', linewidth=2, label='cos(x)')\n",
        "ax.set_title('主图：多个嵌套子图示例', fontsize=16, fontweight='bold')\n",
        "ax.set_xlabel('x 轴', fontsize=12)\n",
        "ax.set_ylabel('y 轴', fontsize=12)\n",
        "ax.grid(True, alpha=0.3)\n",
        "ax.legend()\n",
        "\n",
        "# 嵌套子图 1：放大显示 x=0 附近\n",
        "ax_inset1 = ax.inset_axes([0.05, 0.6, 0.25, 0.3])\n",
        "mask1 = (x >= 0) & (x <= 2)\n",
        "ax_inset1.plot(x[mask1], np.sin(x[mask1]), 'b-', linewidth=2)\n",
        "ax_inset1.plot(x[mask1], np.cos(x[mask1]), 'r-', linewidth=2)\n",
        "ax_inset1.set_xlim(0, 2)\n",
        "ax_inset1.set_ylim(-1.2, 1.2)\n",
        "ax_inset1.set_title('局部视图 1: x=0 附近', fontsize=10, fontweight='bold')\n",
        "ax_inset1.grid(True, alpha=0.3)\n",
        "\n",
        "# 嵌套子图 2：放大显示 x=5 附近\n",
        "ax_inset2 = ax.inset_axes([0.7, 0.6, 0.25, 0.3])\n",
        "mask2 = (x >= 4) & (x <= 6)\n",
        "ax_inset2.plot(x[mask2], np.sin(x[mask2]), 'b-', linewidth=2)\n",
        "ax_inset2.plot(x[mask2], np.cos(x[mask2]), 'r-', linewidth=2)\n",
        "ax_inset2.set_xlim(4, 6)\n",
        "ax_inset2.set_ylim(-1.2, 1.2)\n",
        "ax_inset2.set_title('局部视图 2: x=5 附近', fontsize=10, fontweight='bold')\n",
        "ax_inset2.grid(True, alpha=0.3)\n",
        "\n",
        "# 嵌套子图 3：显示导数信息\n",
        "ax_inset3 = ax.inset_axes([0.7, 0.1, 0.25, 0.3])\n",
        "ax_inset3.plot(x, np.cos(x), 'b--', linewidth=2, label=\"sin'(x) = cos(x)\")\n",
        "ax_inset3.plot(x, -np.sin(x), 'r--', linewidth=2, label=\"cos'(x) = -sin(x)\")\n",
        "ax_inset3.set_title('导数信息', fontsize=10, fontweight='bold')\n",
        "ax_inset3.set_xlabel('x 轴', fontsize=9)\n",
        "ax_inset3.set_ylabel('导数', fontsize=9)\n",
        "ax_inset3.grid(True, alpha=0.3)\n",
        "ax_inset3.legend(fontsize=8)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 2.3 嵌套子图的样式定制\n",
        "\n",
        "可以为嵌套子图添加边框、背景色等样式，使其更加突出。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 6：嵌套子图的样式定制\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 创建主图\n",
        "fig, ax = plt.subplots(figsize=(12, 6))\n",
        "ax.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "ax.set_title('主图：带样式定制的嵌套子图', fontsize=14, fontweight='bold')\n",
        "ax.set_xlabel('x 轴', fontsize=12)\n",
        "ax.set_ylabel('y 轴', fontsize=12)\n",
        "ax.grid(True, alpha=0.3)\n",
        "\n",
        "# 嵌套子图 1：带边框\n",
        "ax_inset1 = ax.inset_axes([0.1, 0.6, 0.3, 0.3])\n",
        "ax_inset1.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "ax_inset1.set_title('带边框的嵌套子图', fontsize=10, fontweight='bold')\n",
        "ax_inset1.grid(True, alpha=0.3)\n",
        "# 添加边框\n",
        "for spine in ax_inset1.spines.values():\n",
        "    spine.set_edgecolor('red')\n",
        "    spine.set_linewidth(2)\n",
        "\n",
        "# 嵌套子图 2：带背景色\n",
        "ax_inset2 = ax.inset_axes([0.6, 0.6, 0.3, 0.3])\n",
        "ax_inset2.plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "ax_inset2.set_title('带背景色的嵌套子图', fontsize=10, fontweight='bold')\n",
        "ax_inset2.set_ylim(-5, 5)\n",
        "ax_inset2.grid(True, alpha=0.3)\n",
        "# 设置背景色\n",
        "ax_inset2.set_facecolor('lightyellow')\n",
        "\n",
        "# 嵌套子图 3：带边框和背景色\n",
        "ax_inset3 = ax.inset_axes([0.35, 0.1, 0.3, 0.3])\n",
        "ax_inset3.plot(x, np.sin(x) * np.cos(x), 'm-', linewidth=2)\n",
        "ax_inset3.set_title('带边框和背景色', fontsize=10, fontweight='bold')\n",
        "ax_inset3.grid(True, alpha=0.3)\n",
        "# 设置背景色和边框\n",
        "ax_inset3.set_facecolor('lightblue')\n",
        "for spine in ax_inset3.spines.values():\n",
        "    spine.set_edgecolor('blue')\n",
        "    spine.set_linewidth(2)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 第三部分：使用场景和最佳实践\n",
        "\n",
        "嵌套子图在数据可视化中有多种应用场景，了解这些场景有助于更好地使用嵌套子图。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 3.1 场景 1：放大显示局部区域\n",
        "\n",
        "这是嵌套子图最常见的用途，用于在主图中突出显示某个区域的细节。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 场景 1：放大显示局部区域\n",
        "# 模拟时间序列数据，在某个时间段有异常值\n",
        "t = np.linspace(0, 100, 1000)\n",
        "signal = np.sin(0.1 * t) + 0.5 * np.cos(0.3 * t)\n",
        "# 在 t=40-50 之间添加异常值\n",
        "signal[(t >= 40) & (t <= 50)] += 2\n",
        "\n",
        "fig, ax = plt.subplots(figsize=(14, 6))\n",
        "ax.plot(t, signal, 'b-', linewidth=1.5, alpha=0.7)\n",
        "ax.set_title('时间序列数据（包含异常值区域）', fontsize=14, fontweight='bold')\n",
        "ax.set_xlabel('时间', fontsize=12)\n",
        "ax.set_ylabel('信号值', fontsize=12)\n",
        "ax.grid(True, alpha=0.3)\n",
        "\n",
        "# 标记异常区域\n",
        "rect = Rectangle((40, ax.get_ylim()[0]), 10, \n",
        "                 ax.get_ylim()[1] - ax.get_ylim()[0],\n",
        "                 linewidth=2, edgecolor='red', \n",
        "                 facecolor='red', alpha=0.2, linestyle='--')\n",
        "ax.add_patch(rect)\n",
        "ax.text(45, ax.get_ylim()[1], '异常区域', fontsize=11, \n",
        "        color='red', ha='center', va='bottom', fontweight='bold')\n",
        "\n",
        "# 嵌套子图：放大显示异常区域\n",
        "ax_inset = ax.inset_axes([0.6, 0.5, 0.35, 0.4])\n",
        "mask = (t >= 40) & (t <= 50)\n",
        "ax_inset.plot(t[mask], signal[mask], 'r-', linewidth=2.5)\n",
        "ax_inset.set_xlim(40, 50)\n",
        "ax_inset.set_ylim(np.min(signal[mask]) - 0.5, np.max(signal[mask]) + 0.5)\n",
        "ax_inset.set_title('异常区域放大视图', fontsize=12, fontweight='bold', color='red')\n",
        "ax_inset.set_xlabel('时间', fontsize=10)\n",
        "ax_inset.set_ylabel('信号值', fontsize=10)\n",
        "ax_inset.grid(True, alpha=0.3)\n",
        "# 添加红色边框突出显示\n",
        "for spine in ax_inset.spines.values():\n",
        "    spine.set_edgecolor('red')\n",
        "    spine.set_linewidth(2)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 3.2 场景 2：显示相关统计信息\n",
        "\n",
        "嵌套子图可以用于显示与主图相关的统计信息、分布图等。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 场景 2：显示相关统计信息\n",
        "# 生成数据\n",
        "np.random.seed(42)\n",
        "data = np.random.normal(100, 15, 1000)\n",
        "\n",
        "fig, ax = plt.subplots(figsize=(12, 6))\n",
        "# 主图：时间序列\n",
        "t = np.arange(len(data))\n",
        "ax.plot(t, data, 'b-', linewidth=1, alpha=0.6)\n",
        "ax.axhline(y=np.mean(data), color='r', linestyle='--', linewidth=2, label=f'均值: {np.mean(data):.2f}')\n",
        "ax.set_title('数据时间序列及统计信息', fontsize=14, fontweight='bold')\n",
        "ax.set_xlabel('时间点', fontsize=12)\n",
        "ax.set_ylabel('数值', fontsize=12)\n",
        "ax.grid(True, alpha=0.3)\n",
        "ax.legend()\n",
        "\n",
        "# 嵌套子图 1：数据分布直方图\n",
        "ax_inset1 = ax.inset_axes([0.05, 0.6, 0.25, 0.3])\n",
        "ax_inset1.hist(data, bins=30, color='skyblue', edgecolor='black', alpha=0.7)\n",
        "ax_inset1.axvline(x=np.mean(data), color='r', linestyle='--', linewidth=2)\n",
        "ax_inset1.set_title('数据分布', fontsize=10, fontweight='bold')\n",
        "ax_inset1.set_xlabel('数值', fontsize=9)\n",
        "ax_inset1.set_ylabel('频数', fontsize=9)\n",
        "ax_inset1.grid(True, alpha=0.3)\n",
        "\n",
        "# 嵌套子图 2：箱线图\n",
        "ax_inset2 = ax.inset_axes([0.7, 0.6, 0.25, 0.3])\n",
        "bp = ax_inset2.boxplot([data], vert=True, patch_artist=True)\n",
        "bp['boxes'][0].set_facecolor('lightgreen')\n",
        "ax_inset2.set_title('箱线图', fontsize=10, fontweight='bold')\n",
        "ax_inset2.set_ylabel('数值', fontsize=9)\n",
        "ax_inset2.grid(True, alpha=0.3, axis='y')\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 3.3 场景 3：对比不同尺度\n",
        "\n",
        "嵌套子图可以用于对比不同时间尺度或不同数据范围的数据。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 场景 3：对比不同尺度\n",
        "# 长期趋势和短期波动\n",
        "t_long = np.linspace(0, 100, 1000)\n",
        "trend = 50 + 0.1 * t_long + 10 * np.sin(0.05 * t_long)  # 长期趋势\n",
        "noise = np.random.randn(len(t_long)) * 2  # 短期噪声\n",
        "data = trend + noise\n",
        "\n",
        "fig, ax = plt.subplots(figsize=(14, 6))\n",
        "ax.plot(t_long, data, 'b-', linewidth=1, alpha=0.7, label='完整数据')\n",
        "ax.plot(t_long, trend, 'r--', linewidth=2, label='趋势线')\n",
        "ax.set_title('长期数据趋势（包含短期波动）', fontsize=14, fontweight='bold')\n",
        "ax.set_xlabel('时间', fontsize=12)\n",
        "ax.set_ylabel('数值', fontsize=12)\n",
        "ax.grid(True, alpha=0.3)\n",
        "ax.legend()\n",
        "\n",
        "# 嵌套子图：显示短期波动细节\n",
        "ax_inset = ax.inset_axes([0.6, 0.5, 0.35, 0.4])\n",
        "# 选择中间一段数据进行放大\n",
        "mask = (t_long >= 40) & (t_long <= 60)\n",
        "ax_inset.plot(t_long[mask], data[mask], 'b-', linewidth=2, label='短期数据')\n",
        "ax_inset.plot(t_long[mask], trend[mask], 'r--', linewidth=2, label='趋势')\n",
        "ax_inset.fill_between(t_long[mask], trend[mask] - 5, trend[mask] + 5, \n",
        "                      alpha=0.2, color='gray', label='波动范围')\n",
        "ax_inset.set_xlim(40, 60)\n",
        "ax_inset.set_title('短期波动细节（放大视图）', fontsize=11, fontweight='bold')\n",
        "ax_inset.set_xlabel('时间', fontsize=10)\n",
        "ax_inset.set_ylabel('数值', fontsize=10)\n",
        "ax_inset.grid(True, alpha=0.3)\n",
        "ax_inset.legend(fontsize=9)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 综合案例\n",
        "\n",
        "下面是一个综合案例，展示嵌套子图在实际数据可视化中的应用。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 综合案例：完整的嵌套子图应用\n",
        "# 模拟股票价格数据\n",
        "np.random.seed(42)\n",
        "days = 252  # 一年的交易日\n",
        "t = np.arange(days)\n",
        "# 生成价格数据：趋势 + 波动\n",
        "price = 100 + 0.1 * t + 20 * np.sin(0.02 * t) + np.cumsum(np.random.randn(days) * 2)\n",
        "\n",
        "fig, ax = plt.subplots(figsize=(16, 8))\n",
        "\n",
        "# 主图：完整的价格走势\n",
        "ax.plot(t, price, 'b-', linewidth=2, alpha=0.8, label='股价')\n",
        "# 计算移动平均\n",
        "ma_20 = np.convolve(price, np.ones(20)/20, mode='valid')\n",
        "ax.plot(t[19:], ma_20, 'r--', linewidth=2, label='20日均线')\n",
        "ax.set_title('股票价格走势图（一年数据）', fontsize=16, fontweight='bold')\n",
        "ax.set_xlabel('交易日', fontsize=12)\n",
        "ax.set_ylabel('价格（元）', fontsize=12)\n",
        "ax.grid(True, alpha=0.3)\n",
        "ax.legend(fontsize=11)\n",
        "\n",
        "# 嵌套子图 1：最近30天的详细视图\n",
        "ax_inset1 = ax.inset_axes([0.05, 0.6, 0.3, 0.3])\n",
        "mask1 = t >= days - 30\n",
        "ax_inset1.plot(t[mask1], price[mask1], 'b-', linewidth=2.5)\n",
        "ma_20_recent = ma_20[-30:]\n",
        "ax_inset1.plot(t[mask1][19:], ma_20_recent, 'r--', linewidth=2)\n",
        "ax_inset1.set_xlim(days - 30, days)\n",
        "ax_inset1.set_title('最近30天详细视图', fontsize=11, fontweight='bold')\n",
        "ax_inset1.set_xlabel('交易日', fontsize=9)\n",
        "ax_inset1.set_ylabel('价格（元）', fontsize=9)\n",
        "ax_inset1.grid(True, alpha=0.3)\n",
        "# 添加边框\n",
        "for spine in ax_inset1.spines.values():\n",
        "    spine.set_edgecolor('blue')\n",
        "    spine.set_linewidth(2)\n",
        "\n",
        "# 嵌套子图 2：价格分布直方图\n",
        "ax_inset2 = ax.inset_axes([0.65, 0.6, 0.3, 0.3])\n",
        "ax_inset2.hist(price, bins=30, color='skyblue', edgecolor='black', alpha=0.7)\n",
        "ax_inset2.axvline(x=np.mean(price), color='r', linestyle='--', linewidth=2, \n",
        "                  label=f'均值: {np.mean(price):.2f}')\n",
        "ax_inset2.set_title('价格分布', fontsize=11, fontweight='bold')\n",
        "ax_inset2.set_xlabel('价格（元）', fontsize=9)\n",
        "ax_inset2.set_ylabel('频数', fontsize=9)\n",
        "ax_inset2.legend(fontsize=8)\n",
        "ax_inset2.grid(True, alpha=0.3)\n",
        "\n",
        "# 嵌套子图 3：收益率分布\n",
        "returns = np.diff(price) / price[:-1] * 100  # 计算收益率（%）\n",
        "ax_inset3 = ax.inset_axes([0.65, 0.1, 0.3, 0.3])\n",
        "ax_inset3.hist(returns, bins=30, color='lightgreen', edgecolor='black', alpha=0.7)\n",
        "ax_inset3.axvline(x=0, color='k', linestyle='-', linewidth=1)\n",
        "ax_inset3.axvline(x=np.mean(returns), color='r', linestyle='--', linewidth=2,\n",
        "                  label=f'均值: {np.mean(returns):.2f}%')\n",
        "ax_inset3.set_title('日收益率分布', fontsize=11, fontweight='bold')\n",
        "ax_inset3.set_xlabel('收益率（%）', fontsize=9)\n",
        "ax_inset3.set_ylabel('频数', fontsize=9)\n",
        "ax_inset3.legend(fontsize=8)\n",
        "ax_inset3.grid(True, alpha=0.3)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 总结\n",
        "\n",
        "本教程详细讲解了 Matplotlib 嵌套子图的创建方法和应用场景：\n",
        "\n",
        "### ✅ 创建嵌套子图的方法\n",
        "- **fig.add_subplot()**：在图形对象上添加子图\n",
        "  - 使用标准网格方式：`fig.add_subplot(nrows, ncols, index)`\n",
        "  - 使用位置元组：`fig.add_subplot([left, bottom, width, height])`\n",
        "\n",
        "- **axes.inset_axes()**：在现有坐标轴内创建嵌套子图（推荐）\n",
        "  - 语法：`ax.inset_axes([x0, y0, width, height])`\n",
        "  - 位置和大小相对于父坐标轴（0-1 之间）\n",
        "  - 更适合在现有子图中添加细节视图\n",
        "\n",
        "### ✅ 主要使用场景\n",
        "1. **放大显示局部区域**：最常用，用于突出显示数据的关键部分\n",
        "2. **显示相关统计信息**：在主图旁显示分布、统计等补充信息\n",
        "3. **对比不同尺度**：同时展示长期趋势和短期波动\n",
        "4. **复杂数据可视化**：创建多层次的图表布局\n",
        "\n",
        "### ✅ 样式定制\n",
        "- 添加边框：通过 `spine.set_edgecolor()` 和 `spine.set_linewidth()`\n",
        "- 设置背景色：使用 `ax.set_facecolor()`\n",
        "- 调整位置和大小：通过 `inset_axes()` 的参数控制\n",
        "\n",
        "### 最佳实践\n",
        "1. 优先使用 `axes.inset_axes()`，代码更简洁\n",
        "2. 嵌套子图的位置要避免遮挡主图的关键信息\n",
        "3. 使用边框或背景色突出嵌套子图\n",
        "4. 保持嵌套子图的标题和标签清晰可读\n",
        "5. 嵌套子图的大小要适中，既能看到细节又不会过于突兀\n",
        "\n",
        "**下一步**：继续学习 Matplotlib 的其他高级功能，如样式和美化、3D 绘图等。\n"
      ]
    }
  ],
  "metadata": {
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}
